﻿using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace Runtime.Common.Utility
{
    public static class AsyncOperationEx
    {
        public static AsyncOperationAwaiter<AsyncOperation> GetAwaiter(this AsyncOperation asyncOperation)
        {
            Error.ThrowArgumentNullException(asyncOperation, $"对象{nameof(asyncOperation)}异步加载错误");
            return new AsyncOperationAwaiter<AsyncOperation>(asyncOperation);
        }

        public struct AsyncOperationAwaiter<T> : ICriticalNotifyCompletion where T : AsyncOperation
        {
            private T asyncOperation;
            private Action continuation;
            private StackTrace capturedStackTrace;

            internal AsyncOperationAwaiter(T asyncOperation)
            {
                this.asyncOperation = asyncOperation;
                this.continuation = null;

                // 在 continuation 被设置时，捕获当前的堆栈信息
                this.capturedStackTrace = new StackTrace(true);
            }


            public bool IsCompleted => asyncOperation.isDone;

            public T GetResult()
            {
                return asyncOperation;
            }

            public void OnCompleted(Action continuation)
            {
                UnsafeOnCompleted(continuation);
            }

            public void UnsafeOnCompleted(Action continuation)
            {
                Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation);

                this.continuation = continuation;
                asyncOperation.completed += OnOperationCompleted;
            }

            private void OnOperationCompleted(AsyncOperation op)
            {
                try
                {
                    continuation?.Invoke();
                }
                catch (Exception e)
                {
                    Debug.LogError($"{nameof(asyncOperation)}异步完成回调失败\n完整堆栈:{e}\n{capturedStackTrace}");
                }
            }
        }
    }
}